#include "GarbageCollector.h"

#include <cassert>
#include <list>
#include "Containers/ForwardLinkedList.h"
#include "Object/Object.h"

#include "Reflection/Type.h"
#include "Reflection/PropertyList.h"
#include "Reflection/GarbageCollectable.h"

#include "Containers/ReflectableMap.h"
#include "Containers/ReflectableVector.h"
#include "Time/CPUTimeCounter.h"

void CGarbageCollector::GarbageCollect()
{
    CODE_BLOCK_TIME_COUNT(U"垃圾回收 CGarbageCollector::GarbageCollect")

    BEGIN_CODE_BLOCK_TIME_COUNT(U"GC:1.找到所有对象")
    //0.find all objects
    std::list<RObject*> AllObjects;

    //将所有对象放入AllObjects
    AllObjects.push_back(WH::GetTransientAsset());
    int64_t ObjectCount=1;

    for(auto& Object : AllObjects)
    {
        auto Children=Object->GetChildren();
        AllObjects.insert(AllObjects.end(), Children.begin(), Children.end());
        ObjectCount+=Children.Num();
    }

    END_CODE_BLOCK_TIME_COUNT()


    BEGIN_CODE_BLOCK_TIME_COUNT(U"GC:2.初始化GC数据")
    //1. init GC data
    for(auto& Object : AllObjects)
    {
        Object->GCReferencedObjects.Clear();
        Object->bGCReachable = false;
        Object->GCReference = 
            Object->GetObjectHead()->RefCounterPtr?
            Object->GetObjectHead()->RefCounterPtr->RefCount
            :0;
    }
    END_CODE_BLOCK_TIME_COUNT()

    BEGIN_CODE_BLOCK_TIME_COUNT(U"GC:3.找到所有引用对象")
    //2. find all referenced objects    
    for(auto& Object : AllObjects)
    {
        RObject* Owner= Object->GetOwner();
        if(Owner)
        {
            Object->GCReferencedObjects.InsertAtHead(Owner);// .Add(Owner);
        }
        
        Object->GetReferencedObjects( Object->GCReferencedObjects);
    }
    END_CODE_BLOCK_TIME_COUNT()

    BEGIN_CODE_BLOCK_TIME_COUNT(U"GC:4.减少引用计数")
    //4. reduce GCReference by referenced objects
    for(auto& Object : AllObjects)
    {
        for(auto& ReferencedObject : Object->GCReferencedObjects)
        {
            ReferencedObject->GCReference--;
        }
    }
    END_CODE_BLOCK_TIME_COUNT()

    BEGIN_CODE_BLOCK_TIME_COUNT(U"GC:5.标记可达对象")
    //5. mark reachable objects
    // if GCReference > 0, mark as reachable 
    //, because it is referenced at other place
    // such as static object, global object, etc.
    for(auto& Object : AllObjects)
    {
        if(Object->GCReference>0)
        {
            TryMarkAsReachable(Object);
        }
    }
    END_CODE_BLOCK_TIME_COUNT()

    BEGIN_CODE_BLOCK_TIME_COUNT(U"GC:6.删除不可达对象")
    //6. delete unreachable objects
    TVector<RObject*> UnreachableObjects;
    UnreachableObjects.Reserve(ObjectCount);
    for(auto& Object : AllObjects)
    {
        if(!Object->bGCReachable)
        {
            UnreachableObjects.Add(Object);
        }
    }
    WH::DestroyObjects(UnreachableObjects);
    
    END_CODE_BLOCK_TIME_COUNT()
}

void CGarbageCollector::TryMarkAsReachable(RObject *InObject)
{
    if(InObject->bGCReachable)
    {
        return;
    }

    InObject->bGCReachable = true;

    for(auto& Referenced: InObject->GCReferencedObjects)
    {
        TryMarkAsReachable(Referenced);
    }

}
